#ifndef LFU_HASH_CACHE_HPP
#define LFU_HASH_CACHE_HPP

#include <vector>
#include <thread>
#include <cmath>

#include "./LfuCache.hpp"

namespace CachePool
{
    // 并没有牺牲空间换时间，只是把原有缓存大小进行了分片。
    template <typename Key, typename Value>
    class LfuHashCache
    {
    public:
        LfuHashCache(const size_t capacity, const size_t sliceNum, const size_t maxAverageFreq = 10)
            : capacity_(capacity),
              sliceNum_(sliceNum > 0 ? sliceNum : std::thread::hardware_concurrency())
        {
            // 每个lfu分片的容量，，分片要多冗余所以上取整
            size_t sliceSize = std::ceil(this->capacity_ / static_cast<double>(this->sliceNum_));
            for (int i = 0; i < sliceNum_; ++i)
            {
                this->lfuSliceCaches_.emplace_back(std::make_unique<LfuCache<Key, Value>>(sliceSize, maxAverageFreq));
            }
        }

        void set(const Key &key, const Value &value)
        {
            // 根据key找出对应的lfu分片
            size_t sliceIndex = this->calcHash(key) % this->sliceNum_;
            return this->lfuSliceCaches_[sliceIndex]->set(key, value);
        }

        bool get(const Key &key, Value &value)
        {
            // 根据key找出对应的lfu分片
            size_t sliceIndex = this->calcHash(key) % this->sliceNum_;
            return this->lfuSliceCaches_[sliceIndex]->get(key, value);
        }

        Value get(const Key &key)
        {
            Value value{};
            this->get(key, value);
            return value;
        }

        // 清除缓存
        void purge()
        {
            for (auto &lfuSliceCache : this->lfuSliceCaches_)
            {
                lfuSliceCache->purge();
            }
        }

    private:
        // 将key计算成对应哈希值
        size_t calcHash(const Key &key)
        {
            std::hash<Key> hashFunc{};
            return hashFunc(key);
        }

    private:
        size_t capacity_;                                                   // 缓存总容量
        size_t sliceNum_;                                                   // 缓存分片数量
        std::vector<std::unique_ptr<LfuCache<Key, Value>>> lfuSliceCaches_; // 缓存lfu分片容器
    };
} // namespace CachePool

#endif // LFU_HASH_CACHE_HPP